home *** CD-ROM | disk | FTP | other *** search
/ Pascal Super Library / Pascal Super Library (CW International)(1997).bin / DELPHI32 / DIALOGS / BROWSEDR / BROWSEDR.PAS < prev    next >
Pascal/Delphi Source File  |  1996-03-17  |  11KB  |  274 lines

  1. {-----------------------------------------------------------------------------}
  2. { A component and a function (use the one you prefer) to encapsulate the      }
  3. { Win95 style directory selection dialog SHBrowseForFolder().                 }
  4. { Copyright 1996, Brad Stowers.  All Rights Reserved.                         }
  5. { This component can be freely used and distributed in commercial and private }
  6. { environments, provied this notice is not modified in any way and there is   }
  7. { no charge for it other than nomial handling fees.  Contact me directly for  }
  8. { modifications to this agreement.                                            }
  9. {-----------------------------------------------------------------------------}
  10. { Feel free to contact me if you have any questions, comments or suggestions  }
  11. { at bstowers@pobox.com or 72733,3374 on CompuServe.                          }
  12. { The lateset version will always be available on the web at:                 }
  13. {   http://www.pobox.com/~bstowers/delphi/delphi.html                         }
  14. {-----------------------------------------------------------------------------}
  15. { Date last modified:  03/17/96                                               }
  16. {-----------------------------------------------------------------------------}
  17.  
  18. { ----------------------------------------------------------------------------}
  19. { TBrowseDirectory v1.00                                                      }
  20. { ----------------------------------------------------------------------------}
  21. { Description:                                                                }
  22. {   A dialog that displays the user's system in a heirarchial manner and      }
  23. {   allows a selection to be made.  It is a wrapper for SHBrowseForFolder(),  }
  24. {   which is rather messy to use directly.                                    }
  25. { Notes:                                                                      }
  26. {   * Requires Pat Ritchey's ShellObj unit.  It is freely available on his    }
  27. {     web site at http://ourworld.compuserve.com/homepages/PRitchey/          }
  28. {   * Callbacks are not implemented in this version.                          }
  29. { ----------------------------------------------------------------------------}
  30. { Revision History:                                                           }
  31. { 1.00:  + Initial release                                                    }
  32. { ----------------------------------------------------------------------------}
  33.  
  34. unit BrowseDr;
  35.  
  36. {$IFNDEF WIN32}
  37.   ERROR!  This unit only available on Win32!
  38. {$ENDIF}
  39.  
  40. interface
  41.  
  42. uses ShellObj, Controls, Classes, DsgnIntf;
  43.  
  44. type
  45.   { These are equivalent to the CSIDL_* constants in the Win32 (95?) API.  }
  46.   { They are used to specify the root of the heirarchy.                    }
  47.   { NOTE: the idDesktopExpanded is not docuemnted, but it seems to be used }
  48.   {       by the Win95 Explorer.  I find it useful, but use at your own    }
  49.   {       risk.  It may be "fixed" in some future release of Win95.        }
  50.   TRootID = (
  51.     idDesktop, idDesktopExpanded, idPrograms, idControlPanel, idPrinters,
  52.     idPersonal, idFavorites, idStartup, idRecent, idSendTo, idRecycleBin,
  53.     idStartMenu, idDesktopDirectory, idDrives, idNetwork, idNetHood, idFonts,
  54.     idTemplates
  55.    );
  56.   { These are equivalent to the BIF_* constants in the Win32 (95?) API.   }
  57.   { They are used to specify what items can be expanded, and what itmes   }
  58.   { can be selected.                                                      }
  59.   TBrowseFlag = (
  60.     bfDirectoriesOnly, bfDomainOnly, bfAncestors, bfComputers, bfPrinters
  61.     { , bfStatusText // Will be added when callback is implemented.       }
  62.    );
  63.   TBrowseFlags = set of TBrowseFlag;
  64.  
  65. { For those of you who prefer to, you can display this dialog with only a }
  66. { function call, no component necessary.  Actually, the component simply  }
  67. { collects parameters and calls this function.                            }
  68. function BrowseDirectory(var   Dest: string;         // Receives selected path
  69.                          const AParent: TWinControl; // Who owns the window
  70.                          const Title: string;        // Text shown above list
  71.                                Root: TRootID;        // Root to browse from
  72.                                Flags: TBrowseFlags   // What is legal to select
  73.                         ): boolean;                  // True if selection made
  74.  
  75. { For the component lover in all of us }
  76. type
  77.   TBrowseDirectoryDlg = class(TComponent)
  78.   private
  79.     { Property variables }
  80.     FTitle: string;
  81.     FRoot: TRootID;
  82.     FOptions: TBrowseFlags;
  83.     { Internal variables }
  84.     FSelected: string;
  85.   public
  86.     constructor Create(AOwner: TComponent); override;
  87.     destructor Destroy; override;
  88.     { Displays the dialog.  Returns true if user selected an item and       }
  89.     { pressed OK, otherwise it returns false.                               }
  90.     function Execute: boolean; virtual;
  91.     { Runtime only property containing the item selected.  This will only   }
  92.     { be valid after Execute is called and it returns TRUE.  At any other   }
  93.     { time, it should be an empty ('') string.                              }
  94.     property Selected: string read FSelected;
  95.   published
  96.     { Text to display above the selection tree.                             }
  97.     property Title: string read FTitle write FTitle;
  98.     { Item that is to be treated as the root of the display.                }
  99.     property Root: TRootID read FRoot write FRoot default idDesktopExpanded;
  100.     { Options to control what is allowed to be selected and expanded.       }
  101.     property Options: TBrowseFlags read FOptions write FOptions default [];
  102.   end;
  103.  
  104.   { A component editor (not really) to allow on-the-fly testing of the      }
  105.   { dialog.  Right click the component and select 'Test Dialog', or simply  }
  106.   { double click the component, and the browse dialog will be displayed     }
  107.   { with the current settings.                                              }
  108.   TBrowseDialogEditor = class(TDefaultEditor)
  109.   public
  110.     procedure ExecuteVerb(Index : Integer); override;
  111.     function GetVerb(Index : Integer): string; override;
  112.     function GetVerbCount : Integer; override;
  113.     procedure Edit; override;
  114.   end;
  115.  
  116. procedure Register;
  117.  
  118. implementation
  119.  
  120. uses Windows, OLE2, Forms, Dialogs, SysUtils;
  121.  
  122. // Utility functions used to convert from Delphi set types to API constants.
  123. function ConvertRoot(Root: TRootID): integer;
  124. const
  125.   RootValues: array[TRootID] of integer = (
  126.     CSIDL_DESKTOP, $0001, CSIDL_PROGRAMS, CSIDL_CONTROLS, CSIDL_PRINTERS,
  127.     CSIDL_PERSONAL, CSIDL_FAVORITES, CSIDL_STARTUP, CSIDL_RECENT, CSIDL_SENDTO,
  128.     CSIDL_BITBUCKET, CSIDL_STARTMENU, CSIDL_DESKTOPDIRECTORY, CSIDL_DRIVES,
  129.     CSIDL_NETWORK, CSIDL_NETHOOD, CSIDL_FONTS, CSIDL_TEMPLATES
  130.    );
  131. begin
  132.   Result := RootValues[Root];
  133. end;
  134.  
  135. function ConvertFlags(Flags: TBrowseFlags): UINT;
  136. const
  137.   FlagValues: array[TBrowseFlag] of UINT = (
  138.     BIF_RETURNONLYFSDIRS, BIF_DONTGOBELOWDOMAIN, BIF_RETURNFSANCESTORS,
  139.     BIF_BROWSEFORCOMPUTER, BIF_BROWSEFORPRINTER
  140.     {, BIF_STATUSTEXT // Will be added when callback is implemented.        }
  141.    );
  142. var
  143.   Opt: TBrowseFlag;
  144. begin
  145.   Result := 0;
  146.   { Loop through all possible values }
  147.   for Opt := Low(TBrowseFlag) to High(TBrowseFlag) do
  148.     if Opt in Flags then
  149.       Result := Result OR FlagValues[Opt];
  150. end;
  151.  
  152.  
  153. function BrowseDirectory(var Dest: string; const AParent: TWinControl;
  154.                          const Title: string; Root: TRootID;
  155.                          Flags: TBrowseFlags): boolean;
  156. var
  157.   ShellMalloc: IMALLOC;
  158.   shBuff: PChar;
  159.   BrowseInfo: TBrowseInfo;
  160.   idRoot, idBrowse: PItemIDList;
  161. begin
  162.   Result := FALSE; // Assume the worst.
  163.   Dest := ''; // Clear it out.
  164.   SetLength(Dest, MAX_PATH);  // Make sure their will be enough room in dest.
  165.   if SHGetMalloc(ShellMalloc) = NOERROR then begin
  166.     try
  167.       shBuff := PChar(ShellMalloc.Alloc(MAX_PATH)); // Shell allocate buffer.
  168.       if assigned(shBuff) then begin
  169.         try
  170.           // Get id for desired root item.
  171.           SHGetSpecialFolderLocation(AParent.Handle, ConvertRoot(Root), idRoot);
  172.           try
  173.             with BrowseInfo do begin  // Fill info structure
  174.               hwndOwner := AParent.Handle;
  175.               pidlRoot := idRoot;
  176.               pszDisplayName := shBuff;
  177.               lpszTitle := PChar(Title);
  178.               ulFlags := ConvertFlags(Flags);
  179.               lpfn := NIL;
  180.               lParam := 0;
  181.             end;
  182.             idBrowse := SHBrowseForFolder(@BrowseInfo);
  183.             if assigned(idBrowse) then begin
  184.               try
  185.                 SHGetPathFromIDList(idBrowse, shBuff); // Turn into real path.
  186.                 Dest := shBuff; // Put it in user's variable.
  187.                 Result := TRUE; // Success!
  188.               finally
  189.                 ShellMalloc.Free(idBrowse); // Clean up after ourselves
  190.               end;
  191.             end;
  192.           finally
  193.             ShellMalloc.Free(idRoot); // Clean-up.
  194.           end;
  195.         finally
  196.           ShellMalloc.Free(shBuff); // Clean-up.
  197.         end;
  198.       end;
  199.     finally
  200.       ShellMalloc.Release; // Clean-up.
  201.     end;
  202.   end;
  203. end;
  204.  
  205.  
  206. constructor TBrowseDirectoryDlg.Create(AOwner: TComponent);
  207. begin
  208.   inherited Create(AOwner);
  209.   FTitle := '';
  210.   FRoot := idDesktopExpanded;
  211.   FOptions := [];
  212.   FSelected := '';
  213. end;
  214.  
  215. destructor TBrowseDirectoryDlg.Destroy;
  216. begin
  217.   inherited Destroy;
  218. end;
  219.  
  220. function TBrowseDirectoryDlg.Execute: boolean;
  221. var
  222.   S: string;
  223.   Parent: TWinControl;
  224. begin
  225.   { Determine who the parent is. }
  226.   if Owner is TWinControl then
  227.     Parent := Owner as TWinControl
  228.   else
  229.     Parent := Application.MainForm;
  230.   { Call the function }
  231.   Result := BrowseDirectory(S, Parent, FTitle, FRoot, FOptions);
  232.   { If selectino made, update property }
  233.   if Result then
  234.     FSelected := S;
  235. end;
  236.  
  237. // Component Editor (not really) to allow on the fly testing of the dialog
  238. procedure TBrowseDialogEditor.ExecuteVerb(Index: Integer);
  239. begin
  240.   {we only have one verb, so exit if this ain't it}
  241.   if Index <> 0 then Exit;
  242.   Edit;
  243. end;
  244.  
  245. function TBrowseDialogEditor.GetVerb(Index: Integer): AnsiString;
  246. begin
  247.   Result := 'Test Dialog';
  248. end;
  249.  
  250. function TBrowseDialogEditor.GetVerbCount: Integer;
  251. begin
  252.   Result := 1;
  253. end;
  254.  
  255. procedure TBrowseDialogEditor.Edit;
  256. begin
  257.   with TBrowseDirectoryDlg(Component) do
  258.     if Execute then
  259.       MessageDlg(Format('Item selected:'#13#13'%s', [Selected]),
  260.                  mtInformation, [mbOk], 0);
  261. end;
  262.  
  263.  
  264. procedure Register;
  265. begin
  266.   { You may prefer it on the Dialogs page, I like it on Win95 because it is
  267.     only available on Win95.                                                }
  268.   RegisterComponents('Win95', [TBrowseDirectoryDlg]);
  269.   RegisterComponentEditor(TBrowseDirectoryDlg, TBrowseDialogEditor);
  270. end;
  271.  
  272.  
  273. end.
  274.